package com.block.common.annotate.impl;

import cn.hutool.core.util.StrUtil;
import com.block.common.annotate.RedisLock;
import com.block.common.service.LogFactory;
import com.block.common.util.SpelUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class RedisLockAspect {
    private Logger logger = LogFactory.getAppReq();
    @Autowired
    RedissonClient redissonClient;
//    @Pointcut("@annotation(com.shanfu.common.annotate.RedisLock)")
//    public void redisLockAspect() {
//    }
private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
    @Around("@annotation(redisLock)")
    public Object doAround(ProceedingJoinPoint pjp, RedisLock redisLock)throws  Throwable{
        String spel=redisLock.key();
        String locKName=redisLock.lockName();
        String lockKey=getRedisKey(pjp,locKName,spel);
        RLock rLock=redissonClient.getLock(lockKey);

       rLock.lock(redisLock.expire(),redisLock.timeUnit());
        Object result = null;
        try {
            //执行方法
            result = pjp.proceed();

        } finally {
            //释放锁
            if(rLock.isLocked()) {
                if(rLock.isHeldByCurrentThread()) {
                    rLock.unlock();
                }
            }
        }
        return result;
    }
    /**
     * 将spel表达式转换为字符串
     * @param joinPoint 切点
     * @return redisKey
     */
    private String getRedisKey(ProceedingJoinPoint joinPoint,String lockName,String spel) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        Object target = joinPoint.getTarget();
        Object[] arguments = joinPoint.getArgs();
        return REDISSON_LOCK_PREFIX + lockName + StrUtil.COLON + SpelUtil.parse(target,spel, targetMethod, arguments);
    }
}
